package controllers

import java.io.File
import java.nio.file.Files

import dao._
import javax.inject.{Inject, Singleton}
import play.api.libs.json.Json
import play.api.mvc.{AbstractController, ControllerComponents, RangeResult}
import utils.Utils.windowsPath
import utils.{ExecCommand, Utils}

import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext}

@Singleton
class DownloadController @Inject()(cc: ControllerComponents,
                                   cpgenomeDao: CpgenomeDao,
                                   chloroplastDao: ChloroplastDao,
                                   mtDao: MtDao,
                                   mtgenomeDao: MtgenomeDao)(implicit exec: ExecutionContext) extends AbstractController(cc) {


  def downloadBeforeUS = Action { implicit request =>
    Ok(views.html.english.download.download())
  }


  def getDownloadJson = Action{implicit request=>
    val mt = Await.result(mtDao.getAll,Duration.Inf)
    val cp = Await.result(chloroplastDao.getAll,Duration.Inf)

    val mtgenome = Await.result(mtgenomeDao.getAll,Duration.Inf).map{x=>
      val mts = mt.find(_.id == x.mtid.toInt).get
      (mts.phylum,mts.classes,x.id,mts.species,x.name)
    }

    val cpgenome = Await.result(cpgenomeDao.getAll,Duration.Inf).map{x=>
      val cps = cp.find(_.id == x.cpid.toInt).get
      (cps.phylum,cps.classes,x.id,cps.species,x.name)
    }

    val mtJson = mtgenome.groupBy(_._1).map{x=>
      val c = x._2.groupBy(_._2).map{y=>
        y._1 -> y._2.map(z=>Json.obj("id"->z._3,"species"->z._4,"genbank" ->z._5,"og"->"mt"))
      }
      x._1 -> c
    }
    val cpJson = cpgenome.groupBy(_._1).map{x=>
      val c = x._2.groupBy(_._2).map{y=>
        y._1 -> y._2.map(z=>Json.obj("id"->z._3,"species"->z._4,"genbank" ->z._5,"og"->"cp"))
      }
      x._1 -> c
    }

    Ok(Json.obj("cp" -> cpJson,"mt"->mtJson))
  }



  def downloadExample(example: String) = Action { implicit request =>
    val filename = "\"" + example + "\""
    Ok.sendFile(new File(Utils.path + "/example/" + example)).withHeaders(
      //缓存
      CACHE_CONTROL -> "max-age=3600",
      CONTENT_DISPOSITION -> ("attachment; filename=" + filename),
      CONTENT_TYPE -> "application/x-download"
    )
  }

  //断点续传
  def linkIgvData(path: String) = Action { implicit request =>
    RangeResult.ofFile(new File(Utils.path + "/igvData/" + path), request.headers.get(RANGE), Some("application/octet-stream"))
  }

  def download(file: String) = Action { implicit request =>
    val name = file.split(" ").mkString("_")
    val filename = "\"" + name + "\""
    Ok.sendFile(new File(Utils.path + "/download/" + name)).withHeaders(
      //缓存
      CACHE_CONTROL -> "max-age=3600",
      CONTENT_DISPOSITION -> ("attachment; filename=" + filename),
      CONTENT_TYPE -> "application/x-download"
    )
  }


  def downloadBlastByRange(name: String, range: String, db: String) = Action {
    val fasta = Utils.path+"/blastData/" + db
    val execCommand = new ExecCommand
    range.split("Range").tail.foreach { x =>
      val r = x.trim.split(":").last.split("to").map(_.trim).sortBy(_.toInt)
      val ra = name + ":" + r.mkString("-")
      val command = if (new File(windowsPath).exists()) {
        Utils.path + "/tools/samtools-0.1.19/samtools.exe faidx "  + fasta + " " + ra
      } else {
        "samtools faidx "  + " " + ra
      }
      execCommand.exec(command)
    }

    val seq = execCommand.getOutStr
    Ok(seq).withHeaders(
      //缓存
      CACHE_CONTROL -> "max-age=3600",
      CONTENT_DISPOSITION -> ("attachment; filename=" + name + ".fasta"),
      CONTENT_TYPE -> "application/x-download"
    )

  }

  def downloadBlastByName(name: String,db:String) = Action {

    val fasta = Utils.path+"/blastData/" + db

    val execCommand = new ExecCommand
    val command = if (new File(windowsPath).exists()) {
      Utils.path + "/tools/samtools-0.1.19/samtools.exe faidx " + fasta + " " + name
    } else {
      "samtools faidx " + fasta + " " + name
    }

    val tmpDir = Files.createTempDirectory("tmpDir").toString
    val seqFile = new File(tmpDir + "/seq.fasta")
    execCommand.execo(command, seqFile)

    println(execCommand.getErrStr)
    Ok.sendFile(seqFile).withHeaders(
      //缓存
      CACHE_CONTROL -> "max-age=3600",
      CONTENT_DISPOSITION -> ("attachment; filename=" + name + ".fasta"),
      CONTENT_TYPE -> "application/x-download"
    )

  }



  def downloadSelect(id:String,og:String,fa:String) = Action { implicit request =>
    val ids =   id.split(",")
    val filename = fa match {
      case "genome" => "genome.fasta"
      case "cds" => "genome.cds"
      case "pep" => "genome.pep"
      case "gb" => "genome.gb"
    }

    val csv =  ids.map { id =>
      Utils.readFileToString(Utils.path + "/download/" + og + "/" + id + "/" + filename).trim
    }.mkString("\n")
    Ok(csv).withHeaders(
      //缓存
      CACHE_CONTROL -> "max-age=3600",
      CONTENT_DISPOSITION -> ("attachment; filename=select." + fa),
      CONTENT_TYPE -> "application/x-download"
    )

  }


  def downloadMtSeqsFile(id:Int,types:String) = Action{implicit request=>
    Ok.sendFile(new File(s"${Utils.path}/download/mt/$id/genome.$types")).withHeaders(
      //缓存
      CACHE_CONTROL -> "max-age=3600",
      CONTENT_DISPOSITION -> s"attachment; filename=genome.$types",
      CONTENT_TYPE -> "application/x-download"
    )
  }

  def downloadCpSeqsFile(id:Int,types:String) = Action{implicit request=>
    Ok.sendFile(new File(s"${Utils.path}/download/cp/$id/genome.$types")).withHeaders(
      //缓存
      CACHE_CONTROL -> "max-age=3600",
      CONTENT_DISPOSITION -> s"attachment; filename=genome.$types",
      CONTENT_TYPE -> "application/x-download"
    )
  }



}
